package com.sgu6.netty;

import android.util.Log;

import com.sgu6.middleware.log.Logger;
import com.sgu6.netty.common.Constant;
import com.sgu6.netty.handler.CommandHandler;
import com.sgu6.netty.handler.FinishOrderHandler;
import com.sgu6.netty.handler.HeartbeatHandler;
import com.sgu6.netty.handler.LoginAdminHandler;
import com.sgu6.netty.handler.LoginHandler;
import com.sgu6.netty.handler.MachineStatusHandler;
import com.sgu6.netty.handler.OperateHandler;
import com.sgu6.netty.protobuffer.NettyMessageProto;
import com.sgu6.middleware.event.MachineStatusEvent;

import org.greenrobot.eventbus.EventBus;

import java.net.InetSocketAddress;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;


public enum NettyClient {

    INSTANCE;
    protected final String TAG = NettyClient.class.getSimpleName();
    EventLoopGroup group;
    public void connect(final String machineNo, final String appVersion, final String host, final int port) {
        group = new NioEventLoopGroup(1);
        Bootstrap b = new Bootstrap();
        b.group(group).channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel arg0) throws Exception {
                        ChannelPipeline pipeline = arg0.pipeline();
                        pipeline.addLast(new ProtobufVarint32FrameDecoder());
                        pipeline.addLast(new ProtobufDecoder(NettyMessageProto.NettyMessage.getDefaultInstance()));
                        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
                        pipeline.addLast(new ProtobufEncoder());
                        pipeline.addLast(new LoginHandler(machineNo, appVersion, host, port));
                        pipeline.addLast(new HeartbeatHandler());
                        pipeline.addLast(new LoginAdminHandler());
                        pipeline.addLast(new MachineStatusHandler());
                        pipeline.addLast(new CommandHandler());
                        pipeline.addLast(new OperateHandler(machineNo));
                        pipeline.addLast(new FinishOrderHandler());
                    }

                });

        try {
            Thread.sleep(Constant.SOCKET_RECONNECT_TIME);
            ChannelFuture future = b.connect(new InetSocketAddress(host, port)).sync();
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            Log.i(TAG, "connect: [" + machineNo + "]连接错误，" + e.getLocalizedMessage());
            group = null;
            b = null;
            EventBus.getDefault().post(new MachineStatusEvent(0));
            connect(machineNo, appVersion, host, port);
        } finally {
            if (group!=null){
                group.shutdownGracefully();  //这里不再是优雅关闭了
            }
        }
    }

    /**
     * 断线重连
     */
    private void reConnectServer(String machineNo, String appVersion, String host, int port) {
        try {
            Thread.sleep(Constant.SOCKET_RECONNECT_TIME);
            Log.i(TAG, "reConnectServer: [" + machineNo + "]客户端进行断线重连");
            connect(machineNo, appVersion, host, port);
        } catch (Exception e) {
            Log.i(TAG, "reConnectServer: " + e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

}
